#ifndef _SPI_C_
#define _SPI_C_

//#include <leon.h>

#include <public/basic_types.h>

#define RTU_SPI_START	0x80000E00
#define RTU_SPI_IRQ		14

/* SPI Address Map */
typedef struct {
	volatile uint32_t Capability;			//Capability register
	volatile uint32_t Reserved0;			//Reserved register 0
	volatile uint32_t Reserved1;			//Reserved register 1
	volatile uint32_t Reserved2;			//Reserved register 2
	volatile uint32_t Reserved3;			//Reserved register 3
	volatile uint32_t Reserved4;			//Reserved register 4
	volatile uint32_t Reserved5;			//Reserved register 5
	volatile uint32_t Reserved6;			//Reserved register 6
	volatile uint32_t Mode;				//Mode register
	volatile uint32_t Event;				//Event register
	volatile uint32_t Mask;				//Mask register
	volatile uint32_t Command;			//Command register
	volatile uint32_t Transmit;			//Transmit register
	volatile uint32_t Receive;			//Receive register
	volatile uint32_t Slave;				//Slave Select register
	volatile uint32_t ASlave;				//Automatic Slave Select register
	volatile uint32_t AM_configuration;	//AM Configuration register
	volatile uint32_t AM_period;			//AM Period register
}RTU_SPI_Registers;

typedef struct {
	uint32_t rtu_spi_up_config_data;
	uint32_t rtu_spi_down_config_data;
}RTU_SPI_CONFIG_DATA;


//SPI MODE REGISTER
typedef enum {
	spiMR_AMEN = 1 << 31,		//Auto Mode Enable
	spiMR_LOOP = 1 << 30,		//Loop Mode Enable
	spiMR_DIV16 = 1 << 27,		//Divide System Clock by 16 Enable
	spiMR_MS = 1 << 25,			//Master Mode Enable
	spiMR_EN = 1 << 24, 		//Enable Core
	spiMR_ASEL = 1 << 14, 		//Automatic Slave Select Enable
	spiMR_FACT = 1 << 13, 		//No Longer compatible with MPC83XX
	spiMR_OD = 1 << 12, 		//Open Drain Mode Enable
	spiMR_TAC = 1 << 14 		//Toggle Automatic Slave Select during Clock Gap
}spi_MODE_REGISTER;

//SPI EVENT REGISTER
typedef enum {
	spiER_TIP = 1 << 31,	//Transfer In Progress
	spiER_LR = 1 << 14,		//Last Character
	spiER_OV = 1 << 12,		//Overrun (Master Mode)
	spiER_UN = 1 << 11,		//Underrun (Slave Mode)
	spiER_MME = 1 << 10,	//Multiple-Master Error
	spiER_NE = 1 << 9,		//Not Empty (Receive Queue)
	spiER_NF = 1 << 8		//Not Full Enable (Transmit Queue)
}spi_EVENT_REGISTER;

//SPI MASK REGISTER
typedef enum {
	spiMKR_TIPE = 1 << 31,		//Transfer In Progress Enable
	spiMKR_LR = 1 << 14,		//Last Character Enable
	spiMKR_OVE = 1 << 12,		//Overrun Enable(Master Mode)
	spiMKR_UNE = 1 << 11,		//Underrun Enable (Slave Mode)
	spiMKR_MMEE = 1 << 10,		//Multiple-Master Error Enable
	spiMKR_NEE = 1 << 9,		//Not Empty Enable(Receive Queue)
	spiMKR_NFE = 1 << 8			//Not Full Enable (Transmit Queue)
}spi_MASK_REGISTER;

//SPI COMMAND REGISTER
typedef enum {
	spiCMR_LAST = 1 << 22		//Enable Event Register Bit LT
}spi_COMMAND_REGISTER;

//RTU SPI SLAVE SELECT
typedef enum {
	GR_RTU_SPI_SLAVE0 = 1,			//Select Slave 0
	GR_RTU_SPI_SLAVE1 = 1 << 1,		//Select Slave 1
	GR_RTU_SPI_SLAVE2 = 1 << 2,		//Select Slave 2
	GR_RTU_SPI_SLAVE3 = 1 << 3,		//Select Slave 3
	GR_RTU_SPI_SLAVE4 = 1 << 4,		//Select Slave 4
	GR_RTU_SPI_SLAVE5 = 1 << 5,		//Select Slave 5
	GR_RTU_SPI_SLAVE6 = 1 << 6,		//Select Slave 6
	GR_RTU_SPI_SLAVE7 = 1 << 7,		//Select Slave 7
	RTU_SPI_SLAVE0 = 0,				//Select Slave 0
	RTU_SPI_SLAVE1 = 1,				//Select Slave 1
	RTU_SPI_SLAVE2 = 2,				//Select Slave 2
	RTU_SPI_SLAVE3 = 3,				//Select Slave 3
	RTU_SPI_SLAVE4 = 4,				//Select Slave 4
	RTU_SPI_SLAVE5 = 5,				//Select Slave 5
	RTU_SPI_SLAVE6 = 6,				//Select Slave 6
	RTU_SPI_SLAVE7 = 7				//Select Slave 7
}RTU_SPI_SLAVE_SELECT;

typedef enum {
    GR_RTU_SPI_3WIRE_ON = 1 << 15,		//Tree-Wire Mode Enable
    GR_RTU_SPI_3WIRE_OFF = 0,			//Tree-Wire Mode Disable
    RTU_SPI_3WIRE_ON = 1,				//Tree-Wire Mode Enable
    RTU_SPI_3WIRE_OFF = 0, 				//Tree-Wire Mode Disnable
    RTU_SPI_3WIRE_MASK = 1 << 15
}RTU_SPI_3WIRE_MODE;

typedef enum {
	GR_RTU_SPI_SCK_312_5K = 0,
	GR_RTU_SPI_SCK_625K = 0,
	GR_RTU_SPI_SCK_1_25M = (spiMR_DIV16 | (0x00000004 << 16)),
	GR_RTU_SPI_SCK_5M = 0,
	GR_RTU_SPI_SCK_10M = 0,
	GR_RTU_SPI_SCK_20M = 0,
	RTU_SPI_SCK_312_5K = 0,
	RTU_SPI_SCK_625K = 1,
	RTU_SPI_SCK_1_25M = 2,
	RTU_SPI_SCK_5M = 3,
	RTU_SPI_SCK_10M = 4,
	RTU_SPI_SCK_20M = 5,
	RTU_SPI_SCK_MASK = (1 << 27 | 1 << 13 | 0x0F << 16)
}RTU_SPI_SCK;

typedef enum {
	GR_RTU_SPI_CLOCK_POLARITY_HIGH = 1 << 29,		//Polarity of SCK clock on the idle state (HIGH)
	GR_RTU_SPI_CLOCK_POLARITY_LOW = 0,				//Polarity of SCK clock on the idle state (LOW)
	RTU_SPI_CLOCK_POLARITY_HIGH = 1,				//Polarity of SCK clock on the idle state (HIGH)
	RTU_SPI_CLOCK_POLARITY_LOW = 0,					//Polarity of SCK clock on the idle state (LOW)
	RTU_SPI_CLOCK_POLARITY_MASK = 1 << 29
}RTU_SPI_CLOCK_POLARITY;

typedef enum {
	GR_RTU_SPI_CLOCK_PHASE_UP = 0,				//Data will be read on the first transition of SCK
	GR_RTU_SPI_CLOCK_PHASE_DOWN = 1 << 28,		//Data will be read on the second transition of SCK
	RTU_SPI_CLOCK_PHASE_UP = 0,					//Data will be read on the first transition of SCK
	RTU_SPI_CLOCK_PHASE_DOWN = 1,				//Data will be read on the second transition of SCK
	RTU_SPI_CLOCK_PHASE_MASK = 1 << 28
}RTU_SPI_CLOCK_PHASE;

typedef enum {
	GR_RTU_SPI_DATA_SIZE_32 = 0,				//32-bit DATA length
	GR_RTU_SPI_DATA_SIZE_16 = 15 << 20,			//16-bit DATA length
	GR_RTU_SPI_DATA_SIZE_15 = 14 << 20,			//15-bit DATA length
	GR_RTU_SPI_DATA_SIZE_14 = 13 << 20,			//14-bit DATA length
	GR_RTU_SPI_DATA_SIZE_13 = 12 << 20,			//13-bit DATA length
	GR_RTU_SPI_DATA_SIZE_12 = 11 << 20,			//12-bit DATA lengthh
	GR_RTU_SPI_DATA_SIZE_11 = 10 << 20,			//11-bit DATA length
	GR_RTU_SPI_DATA_SIZE_10 = 9 << 20,			//10-bit DATA length
	GR_RTU_SPI_DATA_SIZE_9 = 8 << 20,			//9-bit DATA length
	GR_RTU_SPI_DATA_SIZE_8 = 7 << 20,			//8-bit DATA length
	GR_RTU_SPI_DATA_SIZE_7 = 6 << 20,			//11-bit DATA length
	GR_RTU_SPI_DATA_SIZE_6 = 5 << 20,			//10-bit DATA length
	GR_RTU_SPI_DATA_SIZE_5 = 4 << 20,			//9-bit DATA length
	GR_RTU_SPI_DATA_SIZE_4 = 3 << 20,			//8-bit DATA length
	GR_RTU_SPI_BAD_DATA_SIZE = 1 << 15,
	RTU_SPI_DATA_SIZE_4 = 0,					//4-bit DATA length
	RTU_SPI_DATA_SIZE_5 = 1,					//5-bit DATA length
	RTU_SPI_DATA_SIZE_6 = 2,					//6-bit DATA length
	RTU_SPI_DATA_SIZE_7 = 3,					//7-bit DATA length
	RTU_SPI_DATA_SIZE_8 = 4,					//8-bit DATA length
	RTU_SPI_DATA_SIZE_9 = 5,					//9-bit DATA lengthh
	RTU_SPI_DATA_SIZE_10 = 6,					//10-bit DATA length
	RTU_SPI_DATA_SIZE_11 = 7,					//11-bit DATA length
	RTU_SPI_DATA_SIZE_12 = 8,					//12-bit DATA length
	RTU_SPI_DATA_SIZE_13 = 9,					//13-bit DATA length
	RTU_SPI_DATA_SIZE_14 = 10,					//14-bit DATA length
	RTU_SPI_DATA_SIZE_15 = 11,					//15-bit DATA length
	RTU_SPI_DATA_SIZE_16 = 12,					//16-bit DATA length
	RTU_SPI_DATA_SIZE_32 = 13,					//32-bit DATA length
	RTU_SPI_DATA_SIZE_MASK = 0xF << 20
}RTU_SPI_DATA_SIZE;

typedef enum {
	GR_RTU_SPI_MSB_FIRST = 1 << 26,				//Reverse Data Enable (MSB is transmitted first)
	GR_RTU_SPI_LSB_FIRST = 0,					//Reverse Data Disable (LSB is transmitted first)
	RTU_SPI_MSB_FIRST = 1,						//Reverse Data Enable (MSB is transmitted first)
	RTU_SPI_LSB_FIRST = 0,						//Reverse Data Disable (LSB is transmitted first)
	RTU_SPI_ORDER_MASK = 1 << 26
}RTU_SPI_BIT_ORDER;

uint32_t RTU_SPI_Init (RTU_SPI_Registers * SPIDevice);

uint32_t RTU_SPI_Config (RTU_SPI_Registers * SPIDevice, RTU_SPI_3WIRE_MODE three_wire, RTU_SPI_CLOCK_POLARITY sck_polarity,
					  RTU_SPI_CLOCK_PHASE sck_phase, RTU_SPI_SCK sck, RTU_SPI_DATA_SIZE word_size, RTU_SPI_BIT_ORDER order);

RTU_SPI_CONFIG_DATA RTU_SPI_GetConfig (RTU_SPI_Registers * SPIDevice);

uint32_t RTU_SPI_WriteandRead (RTU_SPI_Registers * SPIDevice, RTU_SPI_SLAVE_SELECT slave, RTU_SPI_DATA_SIZE size, uint32_t tdata, uint32_t * rdata);

#endif //_SPI_C_


